#define I686
#include <stdlib.h>
#include "optsemaphore.h"
#include "thread.h"
#include "spinlock.h"
#include "ring_thread_list.h"

struct optsemaphore {
	unsigned int size ;
	unsigned int holding;
	struct list * waiting ;
	spinlock_t door;
	spinlock_t lock;
};

struct optsemaphore * init_optsemaphore(unsigned int size){
	if(size == 0)
		return NULL;
	struct optsemaphore *sem;
	sem=malloc(sizeof (struct optsemaphore));
	sem->size = size ;
	spin_unlock(&sem->lock);
	spin_unlock(&sem->door);
	sem->waiting=NULL;
	return sem;
}

void wait_optsemaphore(struct optsemaphore * sem){
	int key = 0;
	while(spin_trylock(&sem->door));
	if(sem->holding == sem->size){
		sem->waiting=insert(thread_self(),sem->waiting);
		remove_thread_runq(thread_self());
		spin_unlock(&sem->door);
	}else{
		sem->holding++;
		spin_lock(&sem->lock);
		spin_unlock(&sem->door);
	}
}



void post_optsemaphore(struct optsemaphore * sem){
	while(spin_trylock(&sem->door));
	if(!isempty(sem->waiting)){
		thread_t thread = head(shift(sem->waiting));
		if(thread){ add_thread_runq(thread);}
		sem->holding--;
	}
	spin_unlock(&sem->lock);
	spin_unlock(&sem->door);
}


void free_optsemaphore(struct optsemaphore * sem){
	free(sem);
}

